/*********************************************
 All query related functions are handled here
**********************************************/

using namespace std;

/***************************************
 Declared functions ahead of definitions
 to follow grammer sequentially
 ***************************************/
bool relation_name(string name);
bool expr(vector<string> line1);
bool atomic_expr(vector<string> line);
bool selection(vector<string>line);
bool conjunction(vector<string> line, int count);
bool operand(string line);
bool op(string line);
bool Literal(string line);
bool projection(vector<string> line);
bool attribute_list(vector<string> line, int count);
bool renaming(vector<string> line);
bool product(vector<string> line);

bool query(vector<string> line) //checks if it is a query
{    
    if (relation_name(line[0]))// relation name
    { 
		if(line[1]=="<-")// checks for <-
		{       
			if(expr(line))//checks if expr
            {
                return true;
            }
			else
			{
				cout<<"bad expr";
			}
        }
		else
		{
			cout<<"bad <-";
		}
    }
	return false;
}

bool relation_name(string name)// checks if it is a relation name
{   
	int i=0;
	for( i=0; i<name.size(); i++)
	{
		if (!(isalpha(name[i]) || isdigit(name[i]) || name[i]=='_'))// checks for alpha numeris and _
        {
            return false;
        }
		i++;
	}
    return true;
}

 bool expr(vector<string> line )//IT THROWS AWAY THE FIRST TWO ELLEMENTS IN THE VECTOR
 {
	int i=2;
	vector<string> line1;
	while(i<line.size())
	{
		line1.push_back(line[i]);//IT THROWS AWAY THE FIRST TWO ELLEMENTS IN THE VECTOR
		i++;
	}	
	if(atomic_expr(line1)||selection(line1)|| projection(line1)|| renaming(line1)/*||union(line1)||difference(line1) {optional}*/||product(line1))
	{
		return true;
	}
	else
	{
		return false;
	}
}

bool atomic_expr(vector<string> line)
{
	if(line[0]=="(")// checks for expresion within braces
	{
		if(line.back() !=")")
		{
			//error 
		}
		else
		{
			line.insert(line.begin(),"#");
			line.erase(line.end()-1);
			if(expr(line))
			{
				return true;
			}
			else
			{
			// error statement
			}
		}
	}
	if(relation_name(line[0])/*&&(line.size()==1)*/)// checks for relation name
	{
		return true;
	}
	return false;
}

bool selection(vector<string> line)
{
	if(line[0]=="select"|| line[0] == "SELECT")
	{ 
		if(line[1]=="(")
		{ 
			line.erase(line.begin(), line.begin()+2); // deletes the first two ellements in the copy of line passed to select.
			int i=0, count=0;
			while(i<line.size())// counts number of ellements in condition
			{
				if(line[i]==")")
				{
					count=i;
					break;
				}
				i++;
			}
			if(count==0)
			{
			 cout<<"error count=0";
			}
			else
			{ 
				if(conjunction(line,count-1))// also contains condition function
				{ 
					line.erase(line.begin(),line.begin()+count+1);
					if(atomic_expr(line))// checks if the rest is an atomic expresion
					{
						return true;
					}
					else
					{
						//error atomic expr expected after condition
					}
				}
				else
				{
					// incorrect condition
				}
			}
		}
		else
		{
			//missing paranthesis
		}
	}
	return false;
}

bool conjunction(vector<string> line, int count)// also contains condition function
{
	int i=0,check=0;
	if(!(i+2<=count))// checks for opperand op operand 
	{
	check=1;
	}
		while((check==0)&&(i+2<=count))
		{
			check=1;
			if(operand(line[i]))
			{
				if(op(line[++i]))
				{
					if(operand(line[++i]))
					{
						check=0;
						if(i<count)
						{
							if(line[i]=="&&")
							{
								i++;
							}
						}
		
					}
					else
					{
						//opperand missing
					}
				}
				else
				{
					//operation missing
				}
			}
			else
			{
				//error invalid opperand
			}
			if(check==1)
			{
				return false;
			}
		}
		if(check==1)
			{
				return false;
			}
		return true;
	}
	
bool operand(string line)
{ 
	if((line[0] == '\"')&&(line[line.size()-1] == '\"'))// erases the ""
	{
		line.erase(line.begin());
		line.erase(line.end()-1);
	}
	
	if(relation_name(line)||Literal(line))// relationship_name==identifier
	{
		return true;
	}
	return false;
}
bool op(string line)
{
	if(line == "=="||"!= "|| "<" ||">"||"<="||">=")
	{
		return true;
	}
	return false;
}

bool Literal(string name)
{   
	int i=0;

	for(i=0; i<name.size(); i++)
	{
		if (!(isalpha(name[i])||isdigit(name[i]) || name[i] == ' ' || name[i] == '-'))
        {
            return false;
        }
		i++;
	}
    return true;
}

bool projection(vector<string> line)// checks if it is a projection
{
	if(line[0]=="project"||"PROJECT")
	{
		if(line[1]=="(")
		{
			line.erase(line.begin(), line.begin()+2); // deletes the first two ellements in the copy of line passed to select.
			int i=0, count=0;
			while(i<line.size())
			{
				if(line[i]==")")
				{
					count=i;
					break;
				}
				i++;
			}
			if(count==0)
			{
			// error no attribute names
			}
			else
			{
				if(attribute_list(line,count-1))
				{
					line.erase(line.begin(),line.begin()+count+1);
					if(atomic_expr(line))
					{
						return true;
					}
					else
					{
						//error atomic expr expected after condition
					}
				}
				else
				{
					// incorrect attribute names
				}
			}
		}
		else
		{
			//missing paranthesis
		}
	}
	return false;
}

bool attribute_list(vector<string> line, int count)// checks whether the ellemts uptill count are attribute names
{
	int i=0;
	while(i<=count)
	{
		if(!relation_name(line[i]))// atribute name==relation name
		{
			return false;
		}
		i++;
	}
	return true;
}

bool renaming(vector<string> line)
{
	if(line[0]=="rename"||"RENAME")
	{
		if(line[1]=="(")
		{
			line.erase(line.begin(), line.begin()+2); // deletes the first two ellements in the copy of line passed to select.
			int i=0, count=0;
			while(i<line.size())
			{
				if(line[i]==")")
				{
					count=i;
					break;
				}
				i++;
			}
			if(count==0)
			{
			// error no attribute names
			}
			else
			{
				if(attribute_list(line,count-1))
				{
					line.erase(line.begin(),line.begin()+count+1);
					if(atomic_expr(line))
					{
						return true;
					}
					else
					{
						//error atomic expr expected after condition
					}
				}
				else
				{
					// incorrect attribute names
				}
			}
		}
		else
		{
			//missing paranthesis
		}
	}
	return false;
}

bool product(vector<string> line)
{
	int i=0, count=0;vector<string> line1;
		while(i<line.size())
		{
				
			if(line[i]=="*")
			{
				count=i;
				break;
			}
			line1.push_back(line[i]);
			i++;
		}
		if(count!=0)
		{				
			if(atomic_expr(line1))
			{
				if(line[count]=="*")
				{
					line.erase(line.begin(),line.begin()+count+1);
					if(atomic_expr(line))
					{
						return true;
					}
					else
					{
					// atomic_expr is wrong
					}
				}
				else
				{
				//* symbol missing
				}
			}
			else
			{
			// atomic_expr is wrong
			}
		}
	return false;
}	